import React from "react";
import { renderToPipeableStream } from "react-dom/server";
import Html from "./components/Html";
import express from "express";
import {
  createStaticHandler,
  createStaticRouter,
  StaticRouterProvider,
} from "react-router-dom/server";
import routes from "./router";

function createFetchRequest(
  req: express.Request,
  res: express.Response
): Request {
  const origin = `${req.protocol}://${req.get("host")}`;
  // Note: This had to take originalUrl into account for presumably vite's proxying
  const url = new URL(req.originalUrl || req.url, origin);

  const controller = new AbortController();
  res.on("close", () => controller.abort());

  const headers = new Headers();

  for (const [key, values] of Object.entries(req.headers)) {
    if (values) {
      if (Array.isArray(values)) {
        for (const value of values) {
          headers.append(key, value);
        }
      } else {
        headers.set(key, values);
      }
    }
  }

  const init: RequestInit = {
    method: req.method,
    headers,
    signal: controller.signal,
  };

  if (req.method !== "GET" && req.method !== "HEAD") {
    init.body = req.body;
  }

  return new Request(url.href, init);
}

export const render = async (
  request: express.Request,
  response: express.Response,
  bootstrapScripts: string[] = []
) => {
  try {
    const { query, dataRoutes } = createStaticHandler(routes);
    const remixRequest = createFetchRequest(request, response);
    const context = await query(remixRequest);
    if (context instanceof Response) {
      throw context;
    }
    const router = createStaticRouter(dataRoutes, context);
    const { pipe } = renderToPipeableStream(
      <Html>
        <StaticRouterProvider router={router} context={context} />
      </Html>,
      {
        bootstrapScripts,
        onShellReady() {
          response.setHeader("content-type", "text/html");
          pipe(response);
        },
      }
    );
  } catch (error) {
    console.log(error);
  }
};
